/*
 * System:  <???>
 * File:    iic.c
 *          Software implementation for I2C bus master
 *
 * (C) Copyright PinGrid Oy (mi) 1994 - All rights reserved
 *
 *$Id: iic.c 1.1 95/03/03 13:53:06 mi Exp $
 *
 *$Log: iic.c $
 * Revision 1.1  95/03/03  13:53:06  mi
 * Initial revision
 * 
 */

#include "stm32f10x.h"
#include "iic.h"

/*
 * Machine/compiler dependencies. Low level bit banging can be implemented
 * as macros or functions depending on the hardware. This file will
 * use the following macro/function names everywhere.
 */


#define IIC_SDA_PORT	GPIOB
#define IIC_SCL_PORT	GPIOB

#define IIC_SCL_CLK		RRC_APB2Periph_GPIOB
#define IIC_SCL_PIN		GPIO_Pin_9//GPIO_Pin_6

#define IIC_SDA_CLK		RRC_APB2Periph_GPIOB
#define IIC_SDA_PIN		GPIO_Pin_8//GPIO_Pin_7

 
void SCL_H(void);       /* These will be called by iic.c */
void SCL_L(void);
void SDA_H(void);
void SDA_L(void);

bit SCL_IN(void);
bit SDA_IN(void);


 
 /*
 * General i2c delay between most transitions.
 */

void i2c_delay(void)
{
    //int n;
    //n=2;
    //n = 20;
    //n = 200;
    //n = 2000;
    //n = 4000;           /* This delay constant seems to work on a 486DX-50. */
    //n = 8000;          
    //while(n--);
}

/*
 * Bit banging functions. Setting a parallel port output pin high pulls
 * the respective wire low on the I2C bus, while the inputs give
 * the I2C bus state as is. Note that SCL output is connected to the INIT
 * pin, which is inverting.
 */

//============================================================
void SCL_H(void)
{	
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
	
}
void SCL_L(void)
{ 
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
	
	GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_PIN);	
}
bit SCL_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
	
	return (GPIO_ReadInputDataBit(IIC_SCL_PORT,IIC_SCL_PIN));
}
//============================================================
void SDA_H(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);	
}
void SDA_L(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
	
	GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA_PIN);	
}
bit SDA_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);

	return (GPIO_ReadInputDataBit(IIC_SDA_PORT,IIC_SDA_PIN));
}
//============================================================  

byte i2c_error = 0;                 /* Last error */

 
 
bit i2c_reset(void)
{

	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

	GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
	
    SCL_H();i2c_delay();
    SDA_H();i2c_delay();


//Start
    SDA_H();i2c_delay();
    SCL_H();i2c_delay();    
	
	//while(SCL_IN()==0) i2c_delay();//wait device release bus.

    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
    i2c_delay();i2c_delay(); 
//Stop
    SDA_L();i2c_delay();
    SCL_L();i2c_delay();
    SCL_H();i2c_delay();        /* Let SCL go up */

	//while(SCL_IN()==0) i2c_delay();//wait device release bus.

    SDA_H();i2c_delay();        /* ...and then SDA up -> stop condition. */
    i2c_delay();i2c_delay(); 

    i2c_error = 0;
        
    return (SCL_IN() && SDA_IN());
}


/*
 * Send one byte on the bus. No start or stop conditions are generated here,
 * but i2c_error will be set according to the result.
 * Returns 0 on success, 1 if we lose arbitration or if the slave doesn't
 * acknowledge the byte. Check i2c_error for the actual result on error.
 */

bit i2c_byte_out(byte dat)
{
bit ack;
//Data
        SCL_L();i2c_delay();        
    (dat&0x80)? SDA_H():SDA_L();/* Put data out on SDA */
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
    (dat&0x40)? SDA_H():SDA_L();/* Put data out on SDA */
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
    (dat&0x20)? SDA_H():SDA_L();/* Put data out on SDA */
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();        

        SCL_L();i2c_delay();        
    (dat&0x10)? SDA_H():SDA_L();/* Put data out on SDA */
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();        
        
        SCL_L();i2c_delay();        
    (dat&0x08)? SDA_H():SDA_L();/* Put data out on SDA */
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
    (dat&0x04)? SDA_H():SDA_L();/* Put data out on SDA */
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
    (dat&0x02)? SDA_H():SDA_L();/* Put data out on SDA */
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();        

        SCL_L();i2c_delay();        
    (dat&0x01)? SDA_H():SDA_L();/* Put data out on SDA */       
        i2c_delay();
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.
		SCL_L();i2c_delay();
        
        
        
        SDA_H();//Must free the BUS and wait ACK
        i2c_delay();    
        
//ACK
       
        
        SCL_L();i2c_delay();        
        SCL_H();i2c_delay(); 
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.

		ack = SDA_IN();             /* Read in data */     
        SCL_L();i2c_delay();

    
    if (ack)
    {
        i2c_error = I2CERR_NAK;
    }
    return ack;
}


/*
 * Reads one byte in from the slave. Ack must be 1 if this is the last byte
 * to be read during this transfer, 0 otherwise (as per I2C bus specification,
 * the receiving master must acknowledge all but the last byte during a
 * transfer).
 */
 
byte i2c_byte_in(bit ack)
{
bit byte_in;
        byte_in=0;
//Data
        SCL_L();i2c_delay();        
        SCL_H();i2c_delay(); 
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   		
		byte_in = byte_in | ((SDA_IN())?0x80:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
        SCL_H();i2c_delay(); 
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.    
		byte_in = byte_in | ((SDA_IN())?0x40:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
        SCL_H();i2c_delay(); 
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   
		byte_in = byte_in | ((SDA_IN())?0x20:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();    

        SCL_L();i2c_delay();        
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   
		byte_in = byte_in | ((SDA_IN())?0x10:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();    
        
        SCL_L();i2c_delay();        
        SCL_H();i2c_delay(); 
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   
		byte_in = byte_in | ((SDA_IN())?0x08:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
        SCL_H();i2c_delay(); 
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   
		byte_in = byte_in | ((SDA_IN())?0x04:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();

        SCL_L();i2c_delay();        
        SCL_H();i2c_delay(); 
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   
		byte_in = byte_in | ((SDA_IN())?0x02:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();    

        SCL_L();i2c_delay();        
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   
		byte_in = byte_in | ((SDA_IN())?0x01:0x00);             /* Read in data */ 
        SCL_L();i2c_delay();
        
        (ack)?SDA_H():SDA_L();//Must free the BUS and wait ACK
        i2c_delay();i2c_delay();        
        
//ACK
        SCL_L();i2c_delay();        
        SCL_H();i2c_delay();
		//while(SCL_IN()==0) i2c_delay();//wait device release bus.   
        SCL_L();i2c_delay();

        
    SDA_H();             /* Added 18-Jul-95 - thanks to Ray Bellis */
    return byte_in;
}
//#####################################################################
bit i2c_send_one(byte addr, byte reg, byte dat)
{
        //printf("Wr dev=%x,reg=%x,data=%x\n",addr,reg,dat);

//Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay(); 
//Data
        i2c_byte_out(addr&0xfe);
        i2c_byte_out(reg);      
        i2c_byte_out(dat);              
        
//Stop
        SDA_L();i2c_delay();
        SCL_L();i2c_delay();
    SCL_H();i2c_delay();        /* Let SCL go up */
    SDA_H();i2c_delay();        /* ...and then SDA up -> stop condition. */
    i2c_delay();i2c_delay();
        
    return 0;
}
//#####################################################################
bit i2c_recv_one(byte addr, byte reg, byte * pdat)
{
    byte byte_in;
		byte_in=0;

//Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay(); 
//Data
        i2c_byte_out(addr &0xfe);
        i2c_byte_out(reg);      
        
//Re Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay();        

        i2c_byte_out(addr | 0x01);                      
        byte_in= i2c_byte_in(1);   /* No ACK during last byte */
        *pdat = byte_in;        
//Stop
        SDA_L();i2c_delay();
        SCL_L();i2c_delay();
    SCL_H();i2c_delay();        /* Let SCL go up */
    SDA_H();i2c_delay();        /* ...and then SDA up -> stop condition. */
    i2c_delay();i2c_delay();    

        //printf("Rd dev=%x,reg=%x,data=%x\n",addr,reg,byte_in);
    
    return (i2c_error ? 1 : 0);
}
//#####################################################################
bit i2c_send_two(byte addr, byte reg, unsigned short dat)
{
        //printf("Wr dev=%x,reg=%x,data=%x\n",addr,reg,dat);

//Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay(); 
//Data
        i2c_byte_out(addr&0xfe);
        i2c_byte_out(reg);      
        i2c_byte_out(dat>>8);//high byte    
				i2c_byte_out(dat&0xff);  
        
//Stop
        SDA_L();i2c_delay();
        SCL_L();i2c_delay();
    SCL_H();i2c_delay();        /* Let SCL go up */
    SDA_H();i2c_delay();        /* ...and then SDA up -> stop condition. */
    i2c_delay();i2c_delay();
        
    return 0;
}
//#####################################################################
bit i2c_recv_two(byte addr, byte reg, byte * pdat)
{
//Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay(); 
//Data
        i2c_byte_out(addr &0xfe);
        i2c_byte_out(reg);      
        
//Re Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay();        

        i2c_byte_out(addr | 0x01);
				i2c_delay();	
				pdat[1]= i2c_byte_in(0);//high byte       
				i2c_delay();
        pdat[0]= i2c_byte_in(1);   /* No ACK during last byte */        
//Stop
        SDA_L();i2c_delay();
        SCL_L();i2c_delay();
    SCL_H();i2c_delay();        /* Let SCL go up */
    SDA_H();i2c_delay();        /* ...and then SDA up -> stop condition. */
    i2c_delay();i2c_delay();    

        //printf("Rd dev=%x,reg=%x,data=%x\n",addr,reg,byte_in);
    
    return (i2c_error ? 1 : 0);
}
//#####################################################################
bit i2c_recv_eeprom(byte addr, byte reg, byte * pdat)
{
//Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay(); 
//Data
        i2c_byte_out(addr &0xfe);
				i2c_byte_out(0x00);//address high   
        i2c_byte_out(reg);      
        
//Re Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay();        

        i2c_byte_out(addr | 0x01);
				i2c_delay();	
				//pdat[1]= i2c_byte_in(0);//high byte 
				pdat[1]=0;				
				i2c_delay();
        pdat[0]= i2c_byte_in(1);   /* No ACK during last byte */        
//Stop
        SDA_L();i2c_delay();
        SCL_L();i2c_delay();
    SCL_H();i2c_delay();        /* Let SCL go up */
    SDA_H();i2c_delay();        /* ...and then SDA up -> stop condition. */
    i2c_delay();i2c_delay();    

        //printf("Rd dev=%x,reg=%x,data=%x\n",addr,reg,byte_in);
    
    return (i2c_error ? 1 : 0);
}
bit i2c_scan_bus_Nak(byte addr)
{
    byte byte_in;
		byte NAK;
		byte_in=0;
		

//Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
    SDA_L();i2c_delay();        /* Pull SDA down... */
    SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay(); 
//Data
        NAK=i2c_byte_out(addr &0xfe);
				
        i2c_byte_out(0x00);      
        
//Re Start
        SDA_H();i2c_delay();
        SCL_H();i2c_delay();    
				SDA_L();i2c_delay();        /* Pull SDA down... */
				SCL_L();i2c_delay();        /* ...and then SCL -> start condition. */
        i2c_delay();i2c_delay();        

        i2c_byte_out(addr | 0x01);                      
        byte_in= i2c_byte_in(1);   /* No ACK during last byte */
        //*pdat = byte_in;        
//Stop
        SDA_L();i2c_delay();
        SCL_L();i2c_delay();
    SCL_H();i2c_delay();        /* Let SCL go up */
    SDA_H();i2c_delay();        /* ...and then SDA up -> stop condition. */
    i2c_delay();i2c_delay();    

    
    return (NAK);
}
